﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace XNALibrary
{
    public enum WaveDirection
    {
        X = 0,
        Y = 1,
        Z = 2,
        XY = 3,
        XZ = 4,
        YZ = 5,
        XYZ = 6
    }

    public class BenCustomEffect : CustomEffect
    {
        #region Variables

        bool m_bLightingEnabled = true;
        bool m_bWaveEnabled = true;

        Vector3 m_LightPosition;
        float m_fLightPower = 1.0f;
        Color m_Color = Color.Red;

        WaveDirection m_WaveDirection = WaveDirection.Z;
        float m_fWaveHeight = 0.1f;

        float m_fTime = 0.0f;

        bool m_bHasLight1 = false;
        bool m_bHasLight2 = false;
        bool m_bHasLight3 = false;
        bool m_bHasLight4 = false;

        #endregion
        
        #region Properties

        public bool WaveEnabled
        {
            get 
            {
                return m_bWaveEnabled;
            }
            set
            {
                m_bWaveEnabled = value;

                if (CustEffect != null)
                    CustEffect.Parameters["WaveEnabled"].SetValue(value);
            }
        }

        public bool LightsEnabled
        {
            get { return m_bLightingEnabled; }
            set
            {
                m_bLightingEnabled = value;

                if (CustEffect != null)
                    CustEffect.Parameters["LightEnabled"].SetValue(value);
            }
        }

        public bool Light1Enabled
        {
            get
            {
                return CustEffect.Parameters["Light1Enabled"].GetValueBoolean();
            }

            set
            {
                if (CustEffect != null && m_bHasLight1)
                    CustEffect.Parameters["Light1Enabled"].SetValue(value);
            }
        }

        public bool Light2Enabled
        {
            get
            {
                return CustEffect.Parameters["Light2Enabled"].GetValueBoolean();
            }
            set
            {
                if (CustEffect != null && m_bHasLight2)
                    CustEffect.Parameters["Light2Enabled"].SetValue(value);
            }
        }

        public bool Light3Enabled
        {
            get
            {
                return CustEffect.Parameters["Light3Enabled"].GetValueBoolean();
            }
            set
            {
                if (CustEffect != null && m_bHasLight3)
                    CustEffect.Parameters["Light3Enabled"].SetValue(value);
            }
        }

        public bool Light4Enabled
        {
            get
            {
                return CustEffect.Parameters["Light4Enabled"].GetValueBoolean();
            }
            set
            {
                if (CustEffect != null && m_bHasLight4)
                    CustEffect.Parameters["Light4Enabled"].SetValue(value);
            }
        }

        public Vector3 LightPosition
        {
            get { return m_LightPosition; }
            set
            {
                m_LightPosition = value;

                if (CustEffect != null)
                    CustEffect.Parameters["LightPos"].SetValue(value);
            }
        }

        public float LightPower
        {
            get { return m_fLightPower; }
            set
            {
                m_fLightPower = value;

                if (CustEffect != null)
                    CustEffect.Parameters["LightPower"].SetValue(value);
            }
        }

        public Color ModelColor
        {
            get { return m_Color; }
            set
            {
                m_Color = value;

                if (CustEffect != null)
                    CustEffect.Parameters["Color"].SetValue(m_Color.ToVector4());
            }
        }

        public float WaveHeight
        {
            get { return m_fWaveHeight; }
            set
            {
                m_fWaveHeight = value;

                if (CustEffect != null)
                    CustEffect.Parameters["height"].SetValue(value);
            }
        }

        public WaveDirection WaveOreniation
        {
            get { return m_WaveDirection; }
            set
            {
                m_WaveDirection = value;

                if (CustEffect != null)
                    CustEffect.Parameters["Direction"].SetValue(Convert.ToInt32(m_WaveDirection));
            }
        }

        #endregion

        #region Constructor

        public BenCustomEffect(Effect oEffect)
            : base(oEffect)
        {

        }

        #endregion 

        #region Public Methods

        public void AddLights(PointLight[] colLights)
        {
            int iCount = colLights.Length;
            int iIndex = 0;

            //Light 1
            if (iCount > 0 && colLights[iIndex] != null)
            {
                CustEffect.Parameters["LightEnabled"].SetValue(true);

                CustEffect.Parameters["LightPos1"].SetValue(colLights[iIndex].Position);
                CustEffect.Parameters["LightPower1"].SetValue(colLights[iIndex].Intensity);
                CustEffect.Parameters["Color1"].SetValue(colLights[iIndex].Color.ToVector4());
                CustEffect.Parameters["Light1Enabled"].SetValue(true);


                bool f = CustEffect.Parameters["Light1Enabled"].GetValueBoolean();

                m_bHasLight1 = true;

                iIndex++;
                iCount--;
            }
            else
            {
                CustEffect.Parameters["Light1Enabled"].SetValue(false);
                m_bHasLight1 = false;
            }

            //Light 2
            if (iCount > 0 && colLights[iIndex] != null)
            {

                CustEffect.Parameters["LightPos2"].SetValue(colLights[iIndex].Position);
                CustEffect.Parameters["LightPower2"].SetValue(colLights[iIndex].Intensity);
                CustEffect.Parameters["Color2"].SetValue(colLights[iIndex].Color.ToVector4());
                CustEffect.Parameters["Light2Enabled"].SetValue(true);

                m_bHasLight2 = true;

                iIndex++;
                iCount--;
            }
            else
            {
                CustEffect.Parameters["Light2Enabled"].SetValue(false);
                m_bHasLight2 = false;
            }

            //Light 3
            if (iCount > 0 && colLights[iIndex] != null)
            {
                CustEffect.Parameters["LightPos3"].SetValue(colLights[iIndex].Position);
                CustEffect.Parameters["LightPower3"].SetValue(colLights[iIndex].Intensity);
                CustEffect.Parameters["Color3"].SetValue(colLights[iIndex].Color.ToVector4());
                CustEffect.Parameters["Light3Enabled"].SetValue(true);

                m_bHasLight3 = true;

                iIndex++;
                iCount--;
            }
            else
            {
                CustEffect.Parameters["Light3Enabled"].SetValue(false);
                m_bHasLight3 = false;
            }

            //Light 4
            if (iCount > 0 && colLights[iIndex] != null)
            {
                CustEffect.Parameters["LightPos4"].SetValue(colLights[iIndex].Position);
                CustEffect.Parameters["LightPower4"].SetValue(colLights[iIndex].Intensity);
                CustEffect.Parameters["Color4"].SetValue(colLights[iIndex].Color.ToVector4());
                CustEffect.Parameters["Light4Enabled"].SetValue(true);

                m_bHasLight4 = true;

                iIndex++;
                iCount--;
            }
            else
            {
                CustEffect.Parameters["Light4Enabled"].SetValue(false);
                m_bHasLight4 = false;
            }
        }

        public void StartWave(float fLength)
        {
            m_fTime = fLength;

            CustEffect.Parameters["time"].SetValue(fLength);
        }

        #endregion

        #region Override Methods

        public override void SetupParameters()
        {
            if (CustEffect != null)
            {
                CustEffect.Parameters["time"].SetValue(m_fTime);
                CustEffect.Parameters["height"].SetValue(m_fWaveHeight);
                CustEffect.Parameters["Direction"].SetValue(Convert.ToInt32(m_WaveDirection));
                CustEffect.Parameters["WaveEnabled"].SetValue(m_bWaveEnabled);

                if (ModelTexture != null)
                {
                    CustEffect.Parameters["Texture"].SetValue(ModelTexture);
                    CustEffect.Parameters["TextureEnabled"].SetValue(true);
                }
            }
        }

        public override void Update()
        {
            if (m_fTime > 0.0f)
                m_fTime -= 1.0f;
            else
                m_fTime = 0.0f;

            SetupParameters();
        }

        public override void DrawEffect(RigidBody body, RenderControl rc)
        {
            Vector3 CamPos = rc.CurrentCamera.GetPosition();
            Matrix view = rc.CurrentCamera.View;
            Matrix projection = rc.CurrentCamera.Projection;

            ModelMesh mesh;
            ModelMeshPart meshPart;
            GraphicsDevice device = rc.graphicsDevice;
            Model model = body.Model;
                     
            mesh = model.Meshes[0];
            meshPart = mesh.MeshParts[0];

            // set the vertex source to the mesh's vertex buffer
            device.Vertices[0].SetSource(
                mesh.VertexBuffer, meshPart.StreamOffset, meshPart.VertexStride);

            // set the vertex declaration
            device.VertexDeclaration = meshPart.VertexDeclaration;

            // set the current index buffer to the sample mesh's index buffer
            device.Indices = mesh.IndexBuffer;

            CustEffect.Parameters["World"].SetValue(body.GetWorld(mesh));
            CustEffect.Parameters["View"].SetValue(view);
            CustEffect.Parameters["Projection"].SetValue(projection);
            

            CustEffect.Begin();
            foreach (EffectPass pass in CustEffect.CurrentTechnique.Passes)
            {
                pass.Begin();
                device.DrawIndexedPrimitives(
                PrimitiveType.TriangleList, meshPart.BaseVertex, 0,
                meshPart.NumVertices, meshPart.StartIndex, meshPart.PrimitiveCount);
                pass.End();
            }
            CustEffect.End();
        }

        #endregion
    }
}
